#include "usbd_core.h"
#include "board.h"
#include <rtdevice.h>
#include "gt911.h"

#define LCD_WIDTH 800
#define LCD_HEIGHT 480

#define HID_INT_EP          0x84

#pragma pack(push, 1)
// 触摸点结构体，根据HID描述符定义
typedef struct {
    uint8_t tip_switch : 1;      // 触摸开关状态（0=释放，1=按下）
    uint8_t padding : 7;         // 填充位
    uint8_t contact_id;          // Contact Identifier (Usage 0x51)
    uint16_t x;                  // X坐标（范围0-1024）
    uint16_t y;                  // Y坐标（范围0-576）
    uint16_t width;              // 触摸点宽度 (Usage 0x48)
    uint16_t height;             // 触摸点高度 (Usage 0x49)
} touch_point_t;

// 触摸屏输入报告（报告ID 1），支持5个触摸点
typedef struct {
    uint8_t report_id;           // 报告ID = 1
    touch_point_t points[5];     // 5个触摸点（根据HID描述符）
    uint8_t contact_count;       // 当前有效的触摸点数量 (Usage 0x54)
} touch_input_report_t;

// 特性报告（报告ID 2）
typedef struct {
    uint8_t report_id;           // 报告ID = 2
    uint8_t usage_55;            // Usage (0x55)，范围0-16
} touch_feature_report_2_t;
#pragma pack(pop)

USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX touch_input_report_t report;

// 设置触摸点数据
void set_touch_point(uint8_t point_num, uint8_t tip_switch, uint16_t x, uint16_t y)
{
    // 根据LCD分辨率调整到HID描述符定义的范围
    uint16_t scaled_x = (x * 1024) / LCD_WIDTH;
    uint16_t scaled_y = (y * 576) / LCD_HEIGHT;
    
    report.points[point_num].tip_switch = tip_switch;
    report.points[point_num].padding = 0;
    report.points[point_num].contact_id = point_num;
    report.points[point_num].x = scaled_x;
    report.points[point_num].y = scaled_y;
    report.points[point_num].width  = 0x0030;  // 默认值
    report.points[point_num].height = 0x0030;  // 默认值
}

// 清除所有触摸点
void clear_all_touch_points(void)
{
    for (int i = 0; i < 5; i++) {
        report.points[i].tip_switch = 0;
        report.points[i].padding = 0;
        report.points[i].contact_id = i;
        report.points[i].x = 0;
        report.points[i].y = 0;
        report.points[i].width = 0;
        report.points[i].height = 0;
    }
    report.contact_count = 0;
}







 static rt_thread_t  gt911_thread = RT_NULL;
 static rt_sem_t     gt911_sem = RT_NULL;
 static rt_device_t  dev = RT_NULL;
 static struct rt_touch_data *read_data;
 static struct rt_touch_info info;
 
 static void gt911_entry(void *parameter)
 {
    while(usb_device_is_configured(0) == false) {
        rt_thread_mdelay(100);
    }    

    rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, &info);

    read_data = (struct rt_touch_data *)rt_malloc(sizeof(struct rt_touch_data) * info.point_num);

    report.report_id = 1;

    while (1)
    {
        rt_sem_take(gt911_sem, RT_WAITING_FOREVER);

        if (rt_device_read(dev, 0, read_data, info.point_num) == info.point_num)
        {
            report.contact_count = 0;
            // rt_kprintf("info.point_num=%d\n", info.point_num);

            for (rt_uint8_t i = 0; i < info.point_num; i++)
            {
                if (read_data[i].event == RT_TOUCH_EVENT_DOWN || read_data[i].event == RT_TOUCH_EVENT_MOVE)
                {
                    // rt_kprintf("%d %d %d %d %d\n", read_data[i].track_id,
                    //         read_data[i].x_coordinate,
                    //         read_data[i].y_coordinate,
                    //         read_data[i].timestamp,
                    //         read_data[i].width);

                    report.contact_count++;
                    set_touch_point(read_data[i].track_id, 0x01, read_data[i].x_coordinate, read_data[i].y_coordinate);  
                }
                else if (read_data[i].event == RT_TOUCH_EVENT_UP)
                {
                    // 处理触摸抬起事件
                    // rt_kprintf("Touch up: track_id=%d\n", read_data[i].track_id);
                    set_touch_point(read_data[i].track_id, 0x00, 0x00, 0x00);
                }

                usbd_ep_start_write(0, HID_INT_EP, (const uint8_t *)&report, sizeof(touch_input_report_t)); 
                rt_thread_mdelay(1);
            }
        } 
        
        rt_device_control(dev, RT_TOUCH_CTRL_ENABLE_INT, RT_NULL);
    }
 }
 
 static rt_err_t rx_callback(rt_device_t dev, rt_size_t size)
 {
    //  rt_kprintf("irq\n");
     rt_sem_release(gt911_sem);
     rt_device_control(dev, RT_TOUCH_CTRL_DISABLE_INT, RT_NULL);
     return 0;
 }
 

 int gt911_sample(const char *name, rt_uint16_t x, rt_uint16_t y)
 {
     void *id;
 
     dev = rt_device_find(name); 
     RT_ASSERT(rt_device_open(dev, RT_DEVICE_FLAG_INT_RX) == RT_EOK);
 
     id = rt_malloc(sizeof(rt_uint8_t) * 8);
     rt_device_control(dev, RT_TOUCH_CTRL_GET_ID, id);
     rt_uint8_t * read_id = (rt_uint8_t *)id;
     rt_kprintf("id = GT%d%d%d \n", read_id[0] - '0', read_id[1] - '0', read_id[2] - '0');
 
     rt_device_control(dev, RT_TOUCH_CTRL_SET_X_RANGE, &x);  /* if possible you can set your x y coordinate*/
     rt_device_control(dev, RT_TOUCH_CTRL_SET_Y_RANGE, &y);
     rt_device_control(dev, RT_TOUCH_CTRL_GET_INFO, id);
     rt_kprintf("range_x = %d \n", (*(struct rt_touch_info*)id).range_x);
     rt_kprintf("range_y = %d \n", (*(struct rt_touch_info*)id).range_y);
     rt_kprintf("point_num = %d \n", (*(struct rt_touch_info*)id).point_num);
     rt_free(id);
     rt_device_set_rx_indicate(dev, rx_callback);
     gt911_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
 
     gt911_thread = rt_thread_create("gt911",
                                      gt911_entry,
                                      RT_NULL,
                                      1024,
                                      10,
                                      5);
 
    rt_thread_startup(gt911_thread);
 
     return 0;
 }
 
 







